﻿using HHUpdateApp.Properties;
using ICSharpCode.SharpZipLib.Tar;
using ICSharpCode.SharpZipLib.Zip;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SharpCompress.Common;
using SharpCompress.Readers;
using System;
using System.Configuration;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace HHUpdateApp
{
    public partial class UpdateForm : Form
    {
        private RemoteVersionInfo verInfo;
        private UpdateWork work;
        private UpdateForm ThisWindow;
        private bool IsDownLoadFinish = false;

        public UpdateForm(UpdateWork _work)
        {
            uiLabel1.Hide();
            try
            {
                ThisWindow = this;
                InitializeComponent();
                work = _work;
            }
            catch (Exception ex){

                uiLabel1.Show();
                LogManger.Instance.Info("更新程序异常：" + ex.Message);
            }
        }
        public UpdateForm(string _launchAppName, string _checkMode)
        {
            InitializeComponent();
            verInfo = DownloadUpdateInfo(Program.ServerUpdateUrl);
            if(verInfo!=null)
            {
                if(verInfo.ReleaseVersion!= Program.LaunchAppVer)
                {
                    if(!string.IsNullOrEmpty(verInfo.VersionDesc))
                    {
                        this.txtUpdateContent.Visible = true;
                        this.txtUpdateContent.Text = verInfo.VersionDesc;
                    }
                    else
                    {
                        this.txtUpdateContent.Visible = false;
                    }
                    work = new UpdateWork(_launchAppName, verInfo);
                    BGWorkerUpdate.RunWorkerAsync();
                }
                else
                {
                    //直接拉起业务程序
                    string[] AppStartName = verInfo.ApplicationStart.Split('#');
                    foreach (var item in AppStartName)
                    {
                        LogManger.Instance.Info("应用程序重启：启动" + item);
                        Process.Start(Path.Combine(Application.StartupPath, item));

                    }
                    this.Shown += new System.EventHandler(this.UpdateForm_Shown);
                  
                }
            }
            else
            {
                Application.Exit();
            }
            
        }

        private void UpdateForm_Load(object sender, EventArgs e)
        {
            //btnWelcome.Visible = false;


            SetClassLong(this.Handle, GCL_STYLE, GetClassLong(this.Handle, GCL_STYLE) | CS_DropSHADOW); //API函数加载，实现窗体边框阴影效果
        }

        #region 窗体边框阴影效果变量申明
        const int CS_DropSHADOW = 0x20000;
        const int GCL_STYLE = (-26);
        //声明Win32 API
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int SetClassLong(IntPtr hwnd, int nIndex, int dwNewLong);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetClassLong(IntPtr hwnd, int nIndex);
        #endregion

        private void btnWelcome_Click(object sender, EventArgs e)
        {
            work.AppStart();
            this.DialogResult = DialogResult.OK;
        }

        private void UpdateForm_Shown(object sender, EventArgs e)
        {
            this.Close();
        }
        /// <summary>
        /// 下载方法
        /// </summary>
        public void DownLoad()
        {
            
            //从服务器上下载升级文件包
            using (WebClient web = new WebClient())
            {
                try
                {
                    string tempPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"HHUpdateApp\temp\");
                    LogManger.Instance.Info("下载更新程序：下载更新包文件"+ verInfo.ReleaseUrl+"  " + verInfo.ReleaseVersion);
                    //LogManger.Instance.Info("下载更新程序：" + tempPath + verInfo.ReleaseVersion + verInfo.FileType);
                    web.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgressCallback4);
                    web.DownloadFileAsync(new Uri(verInfo.ReleaseUrl), tempPath + verInfo.ReleaseVersion + verInfo.FileType);
                }
                catch (Exception ex)
                {
                    LogManger.Instance.Error("下载更新程序：更新包文件" + verInfo.ReleaseVersion + "下载失败,本次停止更新，异常信息：" + ex);
                    throw ex;
                }

            }
        }
        private string ReadableFilesize(double size)
        {
            String[] units = { "B", "KB", "MB", "GB", "TB", "PB" };
            double mod = 1024.0;
            int i = 0;
            while (size >= mod)
            {
                size /= mod;
                i++;
            }
            return Math.Round(size) + units[i];
        }
        public void DownloadProgressCallback4(object sender, DownloadProgressChangedEventArgs e)
        {
            // Displays the operation identifier, and the transfer progress.
            //Console.WriteLine("downloaded {0} of {1} bytes. {3} % complete...",
            //    e.BytesReceived,
            //    e.TotalBytesToReceive,
            //    e.ProgressPercentage);
            string downmessage = string.Format(@"下载进度 {0} of {1}. {2} % ",
                ReadableFilesize(e.BytesReceived),
                ReadableFilesize(e.TotalBytesToReceive), e.ProgressPercentage);
            int per = 30 + Convert.ToInt32(e.ProgressPercentage * 0.5);
            if(per>100)
            {
                per = 100;
            }
            BGWorkerUpdate.ReportProgress(30+ Convert.ToInt32(e.ProgressPercentage * 0.5), downmessage);
            if(e.BytesReceived== e.TotalBytesToReceive){
                IsDownLoadFinish = true;
            }
        }
        private void BGWorkerUpdate_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            BGWorkerUpdate.ReportProgress(10, "正在升级...");
            //work.Bak();

            Thread.Sleep(500);
            BGWorkerUpdate.ReportProgress(30, "正在下载更新文件...");
            DownLoad();

            while(IsDownLoadFinish==false)
            {
                Thread.Sleep(1000);
            }

            Thread.Sleep(500);
            BGWorkerUpdate.ReportProgress(80, "正在配置更新...");
            Update();

            Thread.Sleep(500);
            BGWorkerUpdate.ReportProgress(100);
        }

        public void Update()
        {
            string tempPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"HHUpdateApp\temp\");
            try
            {
                LogManger.Instance.Info("开始更新程序");
                //如果是全新安装的话，先删除原先的所有程序
                if (verInfo.UpdateMode == "NewInstall")
                {
                    //DelLocal();
                }
                string packageFileName = tempPath + verInfo.ReleaseVersion + verInfo.FileType;

                if (verInfo.FileType.ToLower() == ".zip")
                {
                    using (ZipFile zf = new ZipFile(packageFileName))
                    {
                        foreach (ZipEntry entry in zf)
                        {
                            //一个被压缩文件,称为一个条目
                            Console.WriteLine("压缩包内文件名:" + entry.Name);
                            Console.WriteLine("压缩包大小:" + entry.Size);
                            BGWorkerUpdate.ReportProgress(80, entry.Name);
                            //解压出被压缩的文件
                            if (entry.IsDirectory)
                            {
                                if (!Directory.Exists(Application.StartupPath + "/" + entry.Name.Substring(0, entry.Name.Length - 1)))
                                {
                                    Directory.CreateDirectory(Application.StartupPath + "/" + entry.Name.Substring(0, entry.Name.Length - 1));
                                }
                            }
                            else
                            {
                                FileStream fs = new FileStream(Application.StartupPath + "/" + entry.Name, FileMode.Create);
                                //获取从压缩包中读取数据的流
                                Stream input = zf.GetInputStream(entry);

                                byte[] buffer = new byte[10 * 1024];

                                int length = 0;
                                while ((length = input.Read(buffer, 0, 10 * 1024)) > 0)
                                {
                                    fs.Write(buffer, 0, length);

                                }
                                fs.Close();
                                input.Close();
                            }


                        }
                    }
                }
                else
                {
                    using (var reader = ReaderFactory.Open(File.OpenRead(packageFileName)))
                    {
                        while (reader.MoveToNextEntry())
                        {
                            if (!reader.Entry.IsDirectory)
                            {
                                reader.WriteEntryToDirectory(Application.StartupPath, new ExtractionOptions()
                                {
                                    ExtractFullPath = true,
                                    Overwrite = true
                                });
                            }
                        }
                    }

                }


                LogManger.Instance.Info("更新应用程序：" + verInfo.ReleaseVersion + verInfo.FileType + " 解压完成");
                //using (ZipFile zip = new ZipFile(packageFileName, Encoding.Default))
                //{
                //    zip.ExtractAll(ProgramDirectoryName, ExtractExistingFileAction.OverwriteSilently);
                //    LogManger.Instance.Info("更新应用程序：" + RemoteVerInfo.ReleaseVersion + ".zip" + " 解压完成");
                //}
            }
            catch (Exception ex)
            {
                LogManger.Instance.Error("更新应用程序错误", ex);
                LogManger.Instance.Info("进行回滚操作");
                //Restore();
            }
            finally
            {

                //删除下载的临时文件

                FileInfo file = new FileInfo(tempPath + verInfo.ReleaseVersion + verInfo.FileType);
                file.Delete();
                LogManger.Instance.Info("更新程序：临时文件 " + verInfo.ReleaseVersion + verInfo.FileType + " 删除完成");
            }
        }
        private void BGWorkerUpdate_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            //修改进度条的显示。
            this.updateBar.Value = e.ProgressPercentage;

            //如果有更多的信息需要传递，可以使用 e.UserState 传递一个自定义的类型。
            //这是一个 object 类型的对象，您可以通过它传递任何类型。
            //我们在这里是接受的string 用于在UI界面上显示
            if (e.UserState != null)
            {
                this.lblMsg.Text = e.UserState.ToString();
            }
        }

        private void BGWorkerUpdate_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                this.Close();
            }

            //btnWelcome.Visible = true;


            //过程中的异常会被抓住，在这里可以进行处理。
            if (e.Error == null)
            {
                //btnWelcome.Text = "欢迎使用";
                lblMsg.Text = "程序集版本:" + work.RemoteVerInfo.ReleaseVersion;
                //将新版本更新到config文件中
                Settings.Default.LaunchAppVer = work.RemoteVerInfo.ReleaseVersion;
                Settings.Default.LaunchAppPath = Application.StartupPath;
                Properties.Settings.Default.Save();

                Thread.Sleep(500);           
                work.AppStart();
                Application.Exit();
                //lblAd.Visible = true;
                //lblAd.Text = "程序已经更新为最新版本";
            }
            else
            {
                LogManger.Instance.Error("更新应用程序升级失败：", e.Error);
                lblMsg.Text = e.Error.Message;
                //btnWelcome.Text = "确定";
            }
        }
        private string unicode2CN(string str)
        {
            string outStr = "";
            if (!string.IsNullOrEmpty(str))
            {
                string[] strlist = str.Replace("/", "").Split('u');
                try
                {
                    for (int i = 1; i < strlist.Length; i++)
                    {
                        //将unicode字符转为10进制整数，然后转为char中文字符  
                        outStr += (char)int.Parse(strlist[i], System.Globalization.NumberStyles.HexNumber);
                    }
                }
                catch (FormatException ex)
                {
                    outStr = ex.Message;
                }
            }
            return outStr;
        }
        public  string GetFirstJsonValue(String jsonString, String key)
        {
            string pattern = $"\"{key}\"\\s*:\\s*\"(.*?)\\\"";
            Match match = Regex.Match(jsonString, pattern, RegexOptions.IgnoreCase);
            if (match.Success)
            {
                return match.Groups[1].Value;
            }
            return null;
        }
        private RemoteVersionInfo DownloadUpdateInfo(string serverUrl)
        {
            string updateJson = "";
            using (WebClient updateClt = new WebClient())
            {

                try
                {
                    byte[] bJson = updateClt.DownloadData(serverUrl);
                  
                    updateJson = System.Text.Encoding.UTF8.GetString(bJson).ToString();
                }
                catch (Exception ex)
                {
                    LogManger.Instance.Error("下载服务器上版本信息错误", ex);
                    HHMessageBox.Show(string.Format("升级信息从 {0} 下载失败：{1}", serverUrl, ex.Message), "错误");
                    return null;
                }
                try
                {
                    RemoteVersionInfo info = new RemoteVersionInfo();
                    info.ApplicationStart = GetFirstJsonValue(updateJson, "ApplicationStart");
                    info.ReleaseDate = GetFirstJsonValue(updateJson, "ReleaseDate");
                    info.ReleaseUrl = GetFirstJsonValue(updateJson, "ReleaseUrl");
                    info.ReleaseVersion = GetFirstJsonValue(updateJson, "ReleaseVersion");
                    info.UpdateMode = GetFirstJsonValue(updateJson, "UpdateMode");
                    info.VersionDesc = GetFirstJsonValue(updateJson, "VersionDesc");
                    info.IgnoreFile = GetFirstJsonValue(updateJson, "IgnoreFile");
                    info.FileType = GetFirstJsonValue(updateJson, "FileType");
                    //info = JsonConvert.DeserializeObject<RemoteVersionInfo>(updateJson);
                    return info;
                }
                catch (Exception ex)
                {
                    LogManger.Instance.Error("升级 json 文件错误", ex);
                    HHMessageBox.Show(string.Format("升级 json 文件错误：{0}\r\n{0}", ex.Message, updateJson), "错误");
                    return null;
                }
            }
        }

        private void uiLabel1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}
